package com.example.hoasbackend.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.hoasbackend.common.IndentOperationType;
import com.example.hoasbackend.common.IndentState;
import com.example.hoasbackend.common.SystemOperationCode;
import com.example.hoasbackend.common.utls.RedisUtil;
import com.example.hoasbackend.common.utls.DateTimeUtil;
import com.example.hoasbackend.model.domain.Indent;
import com.example.hoasbackend.model.domain.IndentOperation;
import com.example.hoasbackend.mapper.IndentOperationMapper;
import com.example.hoasbackend.service.IndentOperationService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.hoasbackend.service.IndentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.List;
import java.util.StringTokenizer;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author lhx
 * @since 2022-03-03
 */
@Service
public class IndentOperationServiceImpl extends ServiceImpl<IndentOperationMapper, IndentOperation> implements IndentOperationService {

    @Autowired
    IndentOperationService indentOperationService;

    @Autowired
    IndentService indentService;

    @Autowired
    RedisUtil redisUtil;


    @Autowired
    DateTimeUtil dateTimeUtil;
    @Override
    public void createIndentOperation(Long indentId, Long type, @Nullable String data,
                                      Long userId, Long modifierId) {
        IndentOperation indentOperation=new IndentOperation();
        LocalDateTime localDateTime=LocalDateTime.now();
        indentOperation.setIndentId(indentId);
        indentOperation.setType(type);
        indentOperation.setData(data);
        indentOperation.setDate(localDateTime);
        indentOperation.setUserid(userId);
        indentOperation.setModifierId(modifierId);
        indentOperationService.save(indentOperation);
    }


    @Override
    public long getLastOperationType(long indentId){
        System.out.println("lalala");
        QueryWrapper<IndentOperation> operationQueryWrapper=new QueryWrapper<>();
        System.out.println("hahah");
        operationQueryWrapper.eq("indent_id",indentId).ne("type",IndentOperationType.MODIFYDATE).orderByDesc("date");
        List<IndentOperation> indentOperationList=indentOperationService.list(operationQueryWrapper);
        return indentOperationList.get(0).getType();
    }

    @Override
    public LocalDateTime getCheckInTime(Long indentId) {

        String checkInTimeString=redisUtil.get(indentId+":checkintime");
        String checkOutTimeString=redisUtil.get(indentId+":checkouttime");
        if(!(checkInTimeString==null)){
            return dateTimeUtil.stringtoDateTime(checkInTimeString);
        }
        //从mysql里获取
        String dates=indentOperationService.getCheckTimesString(indentId);
        StringTokenizer stoken=new StringTokenizer(dates,";",false);
        checkInTimeString=stoken.nextToken();
        checkOutTimeString=stoken.nextToken();
        return dateTimeUtil.stringtoDateTime(checkInTimeString);
    }

    @Override
    public LocalDateTime getCheckOutTime(Long indentId) {
        String checkInTimeString=redisUtil.get(indentId+":checkintime");
        String checkOutTimeString=redisUtil.get(indentId+":checkouttime");
        if(!(checkInTimeString==null)){
            return dateTimeUtil.stringtoDateTime(checkOutTimeString);
        }
        //从mysql里获取
        String dates=indentOperationService.getCheckTimesString(indentId);
        StringTokenizer stoken=new StringTokenizer(dates,";",false);
        checkInTimeString=stoken.nextToken();
        checkOutTimeString=stoken.nextToken();
        return dateTimeUtil.stringtoDateTime(checkOutTimeString);
    }

    @Override
    public LocalDateTime getGenerationTime(Long indentId) {
        QueryWrapper<IndentOperation> operationQueryWrapper=new QueryWrapper<>();
        operationQueryWrapper.eq("indent_id",indentId).eq("type",IndentOperationType.CREATE);
        List<IndentOperation> indentOperationList=indentOperationService.list(operationQueryWrapper);
        return indentOperationList.get(0).getDate();
    }
    /**thisstate->nextstate
     *
     * 如果订单超时取消：created->canceled
     *  1.redis：修改订单状态
     *  2. 在sql之中添加operation cancel
     *
     *  paid->checkedin
     *  redis 修改订单装填
     *  需要添加一个新的null的订单idkey
     *
     *  checkedin->checkedout
     *  1. redis：修改订单状态
     */
    @Override
    public void redisKeyExpirationSolution(Long indentBatchId, String thisState, String nextState) {

        redisUtil.set(indentBatchId.toString()+":state",nextState);
        List<Indent> indentBatch=indentService.getListByBatchId(indentBatchId);

        if(nextState.equals(IndentState.CANCELED)){
            for(Indent indent:indentBatch){
                indentOperationService.createIndentOperation(
                        indent.getId(),IndentOperationType.CANCEL,null,indent.getUserId(), SystemOperationCode.SYSTEM_ID);
            }
            redisUtil.set(indentBatchId+":state",IndentState.CANCELED);
            System.out.println(indentBatchId+"Cancel");
        }

        else if(nextState.equals(IndentState.CHECKEDIN)){
            redisUtil.set(indentBatchId+":state",IndentState.CHECKEDIN);
            redisUtil.set(indentBatchId+"","CountingDown",
                    indentOperationService.getExpirationDuration(indentBatchId,IndentState.CHECKEDIN));
        }

        else{//准备checkout
            redisUtil.set(indentBatchId+":state",IndentState.CHECKEDOUT);
            System.out.println(indentBatchId+"checkedout");
        }


    }

    @Override
    /**
     * 获得thisstate到下一个state之间的时间差
     */
    public long getExpirationDuration(Long indentBatchId, String thisState) {
        Long expirationDuration=0L;

        if(thisState.equals(IndentState.CREATED)){
            expirationDuration= RedisUtil.INDENT_EXPIRATION_TIME;
        }else if(thisState.equals(IndentState.PAID)){
           expirationDuration=
                   indentOperationService.getCheckInTime(indentBatchId).toEpochSecond(ZoneOffset.of("+8"))
                           -LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));
        }else if(thisState.equals(IndentState.CHECKEDIN)){
            expirationDuration=
                    indentOperationService.getCheckOutTime(indentBatchId).toEpochSecond(ZoneOffset.of("+8"))
                            -LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));
            System.out.println("check out time last"+expirationDuration);
        }
        if(expirationDuration<0){expirationDuration=0L;}
        return expirationDuration;
    }



    @Override
    public String getCheckTimesString(Long indentId) {
        QueryWrapper<IndentOperation> operationQueryWrapper=new QueryWrapper<>();

        operationQueryWrapper.eq("indent_id",indentId);
        operationQueryWrapper.eq("type",IndentOperationType.CREATE).or().eq("type",IndentOperationType.MODIFYDATE);
        operationQueryWrapper.orderByDesc("date");
        List<IndentOperation> indentOperationList=indentOperationService.list(operationQueryWrapper);
        return indentOperationList.get(0).getData();

    }
}

